/*

*/

#include "../Common/Dispatcher.hpp"
#include "RpcCaller.hpp"
#include "RpcRegistry.hpp"
#include "RpcTopic.hpp"

namespace RpcModule
{
    namespace ClientModule
    {
        // 服务注册客户端
        class RegisterClient
        {
        public:
            using ptr = std::shared_ptr<RegisterClient>;
            // 需要传入注册中心的 IP + 端口
            RegisterClient(const std::string &ip, int port)
                : _requestor(std::make_shared<Requestor>()),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _provider(std::make_shared<ClientModule::Provider>(_requestor))
            {
                // 客户端，需要连接服务端，也要能够获取服务端的应答
                // 1. 设置当收到的是服务应答时的回调函数
                auto OnResponse = std::bind(&Requestor::OnResponse, _requestor.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<BaseMessage>(MType::RSP_SERVICE, OnResponse);
                // 2. 设置客户端收到应答时的回调函数
                auto callback = std::bind(&Dispatcher::OnMessage, _dispatcher.get(),
                                          std::placeholders::_1, std::placeholders::_2);
                // 3. 客户端连接服务端
                _client = MuduoClientFactory::CreateMuduoClient(ip, port);
                _client->SetMessageCallBack(callback);
                _client->Connect();
            }
            // 向外提供的服务注册的接口
            bool RegistryMethod(const std::string &method, const Address &host)
            {
                return _provider->RegistryMethod(_client->GetConnetion(), method, host);
            }

        private:
            Requestor::ptr _requestor; // 注册到Dispatcher -- Service_REQ OnMessage
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;               // 客户端，用于连接服务中心，进行服务注册
            ClientModule::Provider::ptr _provider; // 用于发送服务注册的请求
        };

        // 服务发现客户端
        class DiscoveryClient
        {
        public:
            using ptr = std::shared_ptr<DiscoveryClient>;
            // 用于连接注册中心
            DiscoveryClient(const std::string &ip, int port, const Discoverer::OfflineCallBack &callback)
                : _requestor(std::make_shared<Requestor>()),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _discoverer(std::make_shared<ClientModule::Discoverer>(_requestor, callback))
            {
                // 1. 设置接收到服务应答时的回调函数
                auto OnResponse = std::bind(&Requestor::OnResponse, _requestor.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<BaseMessage>(MType::RSP_SERVICE, OnResponse);
                // 2. 设置接收到服务请求时的回调函数 -- 服务上线/下线通知请求
                auto OnRequest = std::bind(&Discoverer::OnServiceRequest, _discoverer.get(),
                                           std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<ServiceRequest>(MType::REQ_SERVICE, OnRequest);
                // 3. 设置当消息到来时的回调函数
                auto OnMessage = std::bind(&Dispatcher::OnMessage, _dispatcher.get(),
                                           std::placeholders::_1, std::placeholders::_2);
                // 4. 需要创建并启动客户端
                _client = MuduoClientFactory::CreateMuduoClient(ip, port);
                _client->SetMessageCallBack(OnMessage);
                _client->Connect();
            }
            // 向外提供服务发现的接口
            // 将能够提供method服务的主机ip和端口保存在host中
            bool DiscoveryMethod(const std::string &method, Address &host)
            {
                return _discoverer->ServiceDiscovery(_client->GetConnetion(), method, host);
            }

        private:
            Requestor::ptr _requestor; // 注册到Dispatcher -- Service_REQ OnMessage
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;                   // 客户端，用于连接服务中心，进行服务发现
            ClientModule::Discoverer::ptr _discoverer; // 用于发送服务发现的请求
        };

        // Rpc客户端 -- 发送Rpc请求，支持服务发现
        class RpcClient
        {
        public:
            using ptr = std::shared_ptr<RpcClient>;
            // 支持服务发现 -- 传入的是注册中心的IP + 端口
            // 不支持服务发现 -- 直接传入提供服务的服务器的IP + 端口
            RpcClient(bool enablediscovery, const std::string &ip, int port)
                : _enable_discovery(enablediscovery),
                  _requestor(std::make_shared<Requestor>()),
                  _dispatcher(std::make_shared<Dispatcher>()),
                  _caller(std::make_shared<ClientModule::RpcCaller>(_requestor))
            {
                // 1. 注册受到响应时的回调 -- 服务上线/服务下线响应
                auto OnResponse = std::bind(&Requestor::OnResponse, _requestor.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<BaseMessage>(MType::RSP_RPC, OnResponse);
                // 2. 如果支持服务发现，需要初始化服务发现的客户端
                if (_enable_discovery == true)
                {
                    LOGDEBUG("进行服务发现客户端的初始化，%s:%d", ip.c_str(), port);
                    Discoverer::OfflineCallBack callback = std::bind(&RpcClient::DeleteClient, this,
                                                                     std::placeholders::_1);
                    _discovery_client = std::make_shared<DiscoveryClient>(ip, port, callback);
                }
                else
                {
                    // 3. 如果不支持服务发现，那么直接连接服务端即可
                    _client = MuduoClientFactory::CreateMuduoClient(ip, port);
                    auto OnMessage = std::bind(&Dispatcher::OnMessage, _dispatcher.get(),
                                               std::placeholders::_1, std::placeholders::_2);
                    _client->SetMessageCallBack(OnMessage);
                    _client->Connect();
                }
            }
            // 同步发送Rpc调用，并接收结果
            bool Call(const std::string &method, const Json::Value &params, Json::Value &result)
            {
                // 1. 先选择一个客户端，连接服务端
                BaseClient::ptr client = GetClient(method);
                // 2. 发送Rpc请求，并同步获取结果
                if (client.get() == nullptr)
                    return false;
                return _caller->Call(client->GetConnetion(), method, params, result);
            }
            // 异步发送Rpc调用，并接收结果
            bool Call(const std::string &method, const Json::Value &params, RpcCaller::JsonAsyncResponse &result)
            {
                // 1. 先选择一个客户端，连接服务端
                BaseClient::ptr client = GetClient(method);
                // 2. 发送Rpc请求，并异步获取结果
                if (client.get() == nullptr)
                    return false;
                return _caller->Call(client->GetConnetion(), method, params, result);
            }
            // 回调函数发送Rpc调用，并接收结果
            bool Call(const std::string &method, const Json::Value &params, const RpcCaller::JsonCallBackResponse &callback)
            {
                // 1. 先选择一个客户端，连接服务端
                BaseClient::ptr client = GetClient(method);
                // 2. 发送Rpc请求，并执行回调函数
                if (client.get() == nullptr)
                    return false;
                return _caller->Call(client->GetConnetion(), method, params, callback);
            }

        private:
            // 增加客户端
            BaseClient::ptr CreateClient(const Address &host)
            {
                // 1. 新创建一个客户端
                BaseClient::ptr client = MuduoClientFactory::CreateMuduoClient(host.first, host.second);
                // 2. 客户端连接服务端
                auto OnMessage = std::bind(&Dispatcher::OnMessage, _dispatcher.get(),
                                           std::placeholders::_1, std::placeholders::_2);
                client->SetMessageCallBack(OnMessage);
                client->Connect();
                // 3. 然后需要对这个客户端进行管理
                PutClient(host, client);
                return client;
            }
            // 删除客户端
            void DeleteClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.erase(host);
            }
            // 查找客户端
            BaseClient::ptr GetClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _clients.find(host);
                if (it == _clients.end())
                    return BaseClient::ptr();
                return it->second;
            }
            // 选择一个客户端，连接服务端，进行服务调用
            BaseClient::ptr GetClient(const std::string &method)
            {
                BaseClient::ptr client;
                // 1. 需要先知道要连接哪个服务端
                if (_enable_discovery == true)
                {
                    Address host;
                    // 进行服务发现，获取能够提供该服务的服务端信息
                    LOGDEBUG("%d", _discovery_client.get() == nullptr);
                    bool ret = _discovery_client->DiscoveryMethod(method, host);
                    if (ret == false)
                    {
                        LOGERROR("没有找到能够提供%s服务的服务端", method.c_str());
                        return BaseClient::ptr();
                    }
                    // 2. 判断要连接的服务端是否已经存在长连接了
                    client = GetClient(host);
                    // 3. 如果不存在长连接，那么构造一个长连接即可
                    if (client.get() == nullptr)
                        client = CreateClient(host);
                }
                else
                {
                    // 如果不进行服务发现，直接连接服务端
                    client = _client;
                }
                return client;
            }
            void PutClient(const Address &host, BaseClient::ptr &client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.insert(std::make_pair(host, client));
            }

        private:
            struct AddressHash
            {
                size_t operator()(const Address &host) const
                {
                    std::string name = host.first + std::to_string(host.second);
                    return std::hash<std::string>{}(name);
                }
            };
            bool _enable_discovery;                 // 是否支持服务发现 -- 支持需要连接注册中心
            DiscoveryClient::ptr _discovery_client; // 服务发现的客户端
            Requestor::ptr _requestor;              // 注册到Dispatcher -- Service_RSP OnMessage
            Dispatcher::ptr _dispatcher;
            std::mutex _mutex;
            BaseClient::ptr _client;
            ClientModule::RpcCaller::ptr _caller;
            // 对于长连接，一个服务可能有多个连接的客户端，需要进行管理
            std::unordered_map<Address, BaseClient::ptr, AddressHash> _clients;
        };

        class TopicClient
        {
        public:
            using ptr = std::shared_ptr<TopicClient>;
            TopicClient(const std::string& ip, const int& port)
                :_requestor(std::make_shared<Requestor>()),
                _dispatcher(std::make_shared<Dispatcher>()),
                _topic_manager(std::make_shared<TopicManager>(_requestor)) 
            {
                // 1. 注册响应到来时的回调函数
                auto OnResponse = std::bind(&Requestor::OnResponse, _requestor.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<BaseMessage>(MType::RSP_TOPIC, OnResponse);
                // 2. 注册主题请求到来时的回调函数 -- 消息推送请求
                auto OnRequest = std::bind(&TopicManager::OnPublish, _topic_manager.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _dispatcher->RegisterHandler<TopicRequest>(MType::REQ_TOPIC, OnRequest);
                // 3. 注册消息到来时的回调函数
                auto OnMessage = std::bind(&Dispatcher::OnMessage, _dispatcher.get(),
                    std::placeholders::_1, std::placeholders::_2);
                _client = MuduoClientFactory::CreateMuduoClient(ip, port);
                _client->SetMessageCallBack(OnMessage);
                // 4. 客户端连接服务端
                _client->Connect();
            }
            // 创建主题
            bool Create(const std::string& key)
            {
                return _topic_manager->Create(_client->GetConnetion(), key);
            }
            // 删除主题
            bool Remove(const std::string& key)
            {
                return _topic_manager->Remove(_client->GetConnetion(), key);
            }
            // 订阅主题消息
            bool SubScribe(const std::string& key, const TopicManager::TopicCallBack& cb)
            {
                return _topic_manager->SubScribe(_client->GetConnetion(), key, cb);
            }
            // 取消订阅主题
            bool UnSubScribe(const std::string& key)
            {
                return _topic_manager->UnSubScribe(_client->GetConnetion(), key);
            }
            // 主题消息发布
            bool Publish(const std::string& key, const std::string& message)
            {
                return _topic_manager->Publish(_client->GetConnetion(), key, message);
            }
            // 关闭客户端
            void ShutDown()
            {
                _client->ShutDown();
            }
        private:
            Requestor::ptr _requestor; // 注册到Dispatcher -- Topic_Response OnMessage
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;          // 客户端，用于连接服务端
            TopicManager::ptr _topic_manager; // 进行主题的一系列操作
        };
    }
}